import serial #导入模块
import signal
import time
import sys

file_addr = "template.hex"

portx="/dev/ttyUSB0"

bps=115200
#超时设置,None：永远等待操作，0为立即返回请求结果，其他值为等待超时时间(单位为秒）
timex=None



head_code04 = ''
head_code05 = ''
ff='ffffffffffffffffffffffffffffffff'       #填充
dicts='0123456789ABCDEF'                    #字符集
flag=''
sleep_time = 0.00008
buff = 0
flag_time = False


# 自定义超时异常
class TimeoutError(Exception):
    def __init__(self, msg):
        super(TimeoutError, self).__init__()
        self.msg = msg

def time_out(interval, callback):
    def decorator(func):
        def handler(signum, frame):
            raise TimeoutError("等待超时!")
        def wrapper(*args, **kwargs):
            try:
                signal.signal(signal.SIGALRM, handler)
                signal.alarm(interval)       # interval秒后向进程发送SIGALRM信号
                result = func(*args, **kwargs)
                signal.alarm(0)              # 函数在规定时间执行完后关闭alarm闹钟
                return result
            except TimeoutError as e:
                callback(e)
        return wrapper
    return decorator

def timeout_callback(e):
    print(e.msg)






@time_out(1, timeout_callback)
def adjusting(ser):
    ser.write(b'\x7f')
    return ser.read().hex()


def wipe(ser):
    ser.write(b'\x43')
    time.sleep(sleep_time)
    ser.write(b'\xbc')
    return ser.read().hex()


def wipe_add(ser):
    ser.write(b'\xff')
    time.sleep(sleep_time)
    ser.write(b'\x00')
    return ser.read().hex()


def scanf_save_cmd(ser):
    ser.write(b'\x31')
    time.sleep(sleep_time)
    ser.write(b'\xce')
    return ser.read().hex()


def scanf_save_add(ser, addr):
    duf = hex(addr)
    len_s = len(duf)
    if len_s % 2 == 0:
        duf = duf[2:len_s]
    else:
        duf = '0' + duf[2:len_s]
    check = 0
    print(duf,"处理后头部!")
    for n in range((len(duf) // 2)):

        ser.write((int(duf[2*n:2*n + 2], 16)).to_bytes(1, 'big', signed=False))
        #print((int(duf[2*n:2*n + 2], 16)).to_bytes(1, 'big', signed=False),"打印")
        data_a = int(duf[2*n:2*n + 2], 16)
        if n == 0:
            check = data_a
        else:
            check = check ^ data_a
        time.sleep(sleep_time)

    ser.write(check.to_bytes(1, 'big', signed=False))
    print(check.to_bytes(1, 'big', signed=False),'打印较码')

    return ser.read().hex()


def data_scanf(ser, data, duf):
    for n in range(len(data) // 2):
        ser.write((int(data[2*n:2*n + 2], 16)).to_bytes(1, 'big', signed=False))  # 发送

        #print((int(data[2*n:2*n + 2], 16)).to_bytes(1, 'big', signed=False))  #

        duf = duf ^ int(data[2*n:2*n + 2], 16)

        time.sleep(sleep_time)
        # print(hex(duf))

    return duf


def data_scanf_one(ser, data, duf):
    ser.write(duf.to_bytes(1, 'big', signed=False))
    time.sleep(sleep_time)
    return data_scanf(ser, data, duf)


def data_scanf_last(ser, data, duf):
    # print((data_scanf(data, duf)).to_bytes(1, 'big', signed=False))
    ser.write((data_scanf(ser, data, duf)).to_bytes(1, 'big', signed=False))
    return ser.read().hex()


# print(data_scanf_last(data = "08BD0000000C014010B5164816490860",duf = 0xff))


def scanf_main_addr_cmd(ser):
    ser.write(b'\x21')
    time.sleep(sleep_time)
    ser.write(b'\xde')
    return ser.read().hex()


def scanf_main_addr(ser, addr):
    duf = hex(addr)
    len_s = len(duf)
    if len_s % 2 == 0:
        duf = duf[2:len_s]
    else:
        duf = '0' + duf[2:len_s]
    check = 0
    for n in range((len(duf) // 2)):

        ser.write((int(duf[2*n:2*n + 2], 16)).to_bytes(1, 'big', signed=False))
        # print((int(duf[n:n + 2], 16)).to_bytes(1, 'big', signed=False))
        data_a = int(duf[2*n:2*n + 2], 16)
        if n == 0:
            check = data_a
        else:
            check = check ^ data_a
        time.sleep(sleep_time)

    ser.write(check.to_bytes(1, 'big', signed=False))
    # print(check.to_bytes(1, 'big', signed=False))

    return ser.read().hex()

try:
    ser=serial.Serial(portx,bps,timeout=timex)
    f = open(file_addr, mode='r')
    print("连接中!")
    if adjusting(ser) == None:
        print("烧录前请复位!")
        f.close()
        ser.close()
        sys.exit()

    print(wipe(ser),"擦除中！")
    print(wipe_add(ser),"擦除成功！")

    data = f.readline()
    while not (":00000001FF" in data):
        if data[0:1] == ':':
            pass
        else:
            continue
        data_len = int(data[1:3], 16)

        if data[7:9] == '04':
            head_code04 = (int(data[9:9 + 2 * data_len], 16)) << 16
            print(hex(head_code04),"头部检测成功！")
        if data[7:9] == '00':
            flag = data[5:6]
            if (data_len == 16):
                data16 = data[9:9 + 2 * data_len]
            else:
                data16 = data[9:9 + 2 * data_len] + ff[0:32 - 2 * data_len]
            if flag == '0':
                #print(hex(head_code04))
                print(scanf_save_cmd(ser),"发送写数据指令！")
                print(scanf_save_add(ser,head_code04),"地址成功校准！")
                buff = data_scanf_one(ser,data16,0xff)
                head_code04 += 0x100
                #print(data16)
            elif flag == 'F':
                print(data_scanf_last(ser, data16, buff),"完成烧录一组数据！")
            else:
                buff = data_scanf(ser, data16, buff)
                print(data16,"正在烧录数据！")
        if data[7:9] == '05':
            head_code05 = data[9:9 + 2 * data_len]

        # print(data)
        data = f.readline()

    #print(flag)
    if flag == 'f' or flag == 'F':
        print('烧录成功')
    else:
        #print(16 - (dicts.index(flag) + 1))
        for i in range(16 - (dicts.index(flag) + 1)):
            if (((dicts.index(flag) + 1))+i) == 15:
                print(ff,"最后一条！")
                print(data_scanf_last(ser, ff, buff), "完成烧录一组数据！")
            else:
                buff = data_scanf(ser, ff, buff)
                print(ff,hex(buff))

    #print(head_code05)
    print(scanf_main_addr_cmd(ser),"发送入口")
    print(scanf_main_addr(ser,int(head_code05,16)),"入口地址发送成功")

    print("烧录成功！！！！！！！")
    f.close()



    ser.close()#关闭串口
except Exception as e:
    print("---异常---：",e)
